import { isObject } from '@/utils/verify';

/**
 * 数组对象去重 (根据某个字段去重)
 * @param arr - 需要去重的数组
 * @param key - 需要根据那个字段去重
 */
export function filterRepeat<T extends Record<number | string | symbol, unknown>, K extends keyof T>(arr: T[], key: K): T[] {
  const res = new Map<unknown, 1>();
  return arr.filter((item) => !res.has(item[key]) && res.set(item[key], 1));
}

/**
 * 根据key合并数组去掉重复
 * 有重复的就保留arr2的
 */
export function mergeArrFun<T extends Record<string, unknown>, K extends keyof T>(arr1: T[], arr2: T[], key: K): T[] {
  const res = new Map<unknown, T>();
  arr1.forEach((item) => {
    res.set(item[key], item);
  });
  arr2.forEach((item) => {
    res.set(item[key], item);
  });
  const arr: T[] = [];

  res.forEach((val) => {
    arr.push(val);
  });
  return arr;
}

/**
 * 根据路径获取对象的值
 * @param obj - 对象
 * @param path - 如 'a.c'只支持点路径,不支持 'a[0]'
 */
export function getValueByPath(obj: Record<string, unknown>, path: string): unknown {
  const paths = path.split('.');
  let res: Record<string, unknown> = obj;
  let result: unknown = '';
  paths.forEach((item: string) => {
    if (item in res && typeof res[item] === 'object') {
      res = res[item] as Record<string, unknown>;
    } else {
      result = res[item];
    }
  });
  return result;
}

/**
 * 根据路径 或一个路径数组得到一个由该路径值组成的一个字符串  (多由于唯一字段)
 * @param obj - 对象
 * @param paths - 如 ['a.c','a' 'a.c.d']只支持点路径,不支持 ['a[0]']
 */
export function getOnlyValue(obj: Record<string, unknown>, paths: string[] | string): string {
  if (Array.isArray(paths)) {
    let onlyValue = '';
    paths.forEach((key) => {
      onlyValue += `_${String(getValueByPath(obj, key)) || ''}`;
    });
    return onlyValue;
  } else {
    return obj[paths] as string;
  }
}

/**
 * 删除指定的元素并返回删除后的数组 [用于需要返回新数组而不是直接修改原数组的情况]
 */
export function mySplice<T>(array: T[], index: number): T[] {
  return array.slice(0, index).concat(array.slice(index + 1));
}

/**
 * 在数组后面添加一个元素并返回添加后的数组 [用于需要返回新数组而不是直接修改原数组的情况]
 */
export function myPush<T>(array: T[], item: T): T[] {
  return array.concat([item]);
}

/**
 * 特定的值删除数组中的元素并返回删除后的数组 [用于需要返回新数组而不是直接修改原数组的情况]
 */
export function myDelItem<T>(array: T[], item: T): T[] {
  const index = array.indexOf(item);
  return index >= 0 ? mySplice(array, index) : array;
}

/**
 * 得到两个数组的交集
 */
export function myGetIntersection<T>(arr1: T[], arr2: T[]): T[] {
  if (Array.isArray(arr1) && Array.isArray(arr2)) {
    return arr1.filter((item) => arr2.includes(item));
  } else {
    return [];
  }
}

/**
 * 判断两个数组是否有交集
 */
export function myHaveIntersection<T = unknown>(arr1: T[], arr2: T[]): boolean {
  if (Array.isArray(arr1) && Array.isArray(arr2)) {
    const index = arr1.findIndex((item) => arr2.includes(item));
    return index >= 0;
  } else {
    return false;
  }
}

/**
 * 判断两个对象内容是否相等
 * @param obj1 - 需要判断的对象1
 * @param obj2 - 需要判断的对象2
 * @param notComparisonParam - notComparisonParam  不判断对象中的那些字段 [字符串数组]
 */
export function myEqual(obj1: unknown, obj2: unknown, notComparisonParam: string[] = []): boolean {
  // 判断两个对象是否指向同一内存或者全等,指向同一内存或全等返回true
  if (obj1 === obj2) {
    return true;
  }
  // 类型相同才比较,不同则直接返回false
  const obj1Type = typeof obj1;
  const obj2Type = typeof obj2;
  // 注意 null 的typeof 也为 'object'
  if (obj1Type === obj2Type && obj1 !== null && obj2 !== null) {
    if (isObject(obj1) && isObject(obj2)) {
      const a = JSON.parse(JSON.stringify(obj1));
      const b = JSON.parse(JSON.stringify(obj2));
      notComparisonParam.forEach((item) => {
        delete a[item];
        delete b[item];
      });
      // 获取两个对象键值数组
      const aProps = Object.getOwnPropertyNames(a);
      const bProps = Object.getOwnPropertyNames(b);
      // 判断两个对象键值数组长度是否一致,不一致返回false
      if (aProps.length !== bProps.length) {
        return false;
      }
      // 遍历对象的键值
      for (const prop in a) {
        // 判断a的键值,在b中是否存在,不存在,返回false
        if (Object.hasOwn(b, prop)) {
          // 判断a的键值是否为对象,是则递归,不是对象直接判断键值是否相等,不相等返回false
          if (isObject(a[prop])) {
            if (!myEqual(a[prop], b[prop])) {
              return false;
            }
          } else if (a[prop] !== b[prop]) {
            return false;
          }
        } else {
          return false;
        }
      }
      return true;
    } else {
      // 不是对象且上面已经判断了不全等则返回false
      return false;
    }
  } else {
    return false;
  }
}

/**
 * 把字符串转为Json对象
 */
export function myStrToJson<T = Record<string, unknown>>(obj: T | string): T | false {
  if (typeof obj === 'string') {
    try {
      return JSON.parse(obj) as T;
    } catch (err) {
      return false;
    }
  } else {
    return false;
  }
}

/**
 * 反转对象的键值对(不会改变原对象)
 */
export function invertObjKeyValues<T extends Record<string, string>>(obj: T) {
  const newObj: Record<string, string> = {};
  for (const key in obj) {
    const val = obj[key];
    if (val) {
      newObj[val] = key;
    }
  }
  return newObj;
}

/**
 * 判断两个对象内容是否相等
 * @param obj1 - 需要判断的对象1
 * @param obj2 - 需要判断的对象2
 * @param notComparisonParam - notComparisonParam  不判断对象中的那些字段 [字符串数组]
 */
export function isEqual(obj1: unknown, obj2: unknown, notComparisonParam: string[] = []): boolean {
  // 判断两个对象是否指向同一内存或者全等,指向同一内存或全等返回true
  if (obj1 === obj2) {
    return true;
  }
  // 类型相同才比较,不同则直接返回false
  const obj1Type = typeof obj1;
  const obj2Type = typeof obj2;
  // 注意 null 的typeof 也为 'object'
  if (obj1Type === obj2Type && obj1 !== null && obj2 !== null) {
    if (isObject(obj1) && isObject(obj2)) {
      const a = JSON.parse(JSON.stringify(obj1));
      const b = JSON.parse(JSON.stringify(obj2));
      notComparisonParam.forEach((item) => {
        delete a[item];
        delete b[item];
      });
      // 获取两个对象键值数组
      const aProps = Object.getOwnPropertyNames(a);
      const bProps = Object.getOwnPropertyNames(b);
      // 判断两个对象键值数组长度是否一致,不一致返回false
      if (aProps.length !== bProps.length) {
        return false;
      }
      // 遍历对象的键值
      for (const prop in a) {
        // 判断a的键值,在b中是否存在,不存在,返回false
        if (Object.hasOwn(b, prop)) {
          // 判断a的键值是否为对象,是则递归,不是对象直接判断键值是否相等,不相等返回false
          if (isObject(a[prop])) {
            if (!isEqual(a[prop], b[prop])) {
              return false;
            }
          } else if (a[prop] !== b[prop]) {
            return false;
          }
        } else {
          return false;
        }
      }
      return true;
    } else {
      // 不是对象且上面已经判断了不全等则返回false
      return false;
    }
  } else {
    return false;
  }
}

export function blobToString(blob: Blob): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      resolve(reader.result as string);
    };
    reader.onerror = () => {
      reject(new Error('Error converting Blob to string'));
    };
    reader.readAsText(blob); // 使用readAsText读取文本内容
  });
}
